package com.weixing.mall.provider.controller;

import com.weixing.mall.base.constant.GlobalConstant;
import com.weixing.mall.base.enums.ResultCodeEnum;
import com.weixing.mall.base.wrapper.Result;
import com.weixing.mall.base.wrapper.ResultUtil;
import com.weixing.mall.core.support.BaseController;
import com.weixing.mall.provider.support.wechat.WechatUtil;
import com.weixing.mall.provider.token.RefreshTokenServices;
import com.weixing.mall.provider.util.UaaUtil;
import com.weixing.oauth2.common.userdetails.IUserAuthService;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.web.bind.annotation.*;
import org.weixin4j.model.js.WxConfig;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 文件上传通用类
 *
 * @Author: kfc
 * @Description: <br/>
 * Date:Create in 2019/8/21 16:37
 * @Modified By:
 */

@RestController
@RequestMapping("")
public class AuthController extends BaseController {

    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private IUserAuthService memberAuthService;
    @Autowired
    private IUserAuthService sysUserAuthService;
    @Autowired
    private RefreshTokenServices sysTokenServices;
    @Autowired
    private IUserAuthService agentAuthService;
    @Resource(name = "jwtAccessTokenConverter")
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @PostMapping("/token/refresh")
    public Result<OAuth2AccessToken> refreshToken(HttpServletRequest request, String refreshToken) throws IOException {
        // 解析Header
        String header = request.getHeader(HttpHeaders.AUTHORIZATION);

        if (header == null && !header.startsWith(GlobalConstant.BASIC_AUTH)) {
            throw new UnapprovedClientAuthenticationException("请求投中无client信息");
        }
        String[] tokens = UaaUtil.extractAndDecodeHeader(header);
        assert tokens.length == 2;
        //获取clientId 和 clientSecret
        String clientId = tokens[0];
        String clientSecret = tokens[1];
        //获取 ClientDetails
        ClientDetails clientDetails = getClient(clientId, clientSecret, clientDetailsService);
        TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "customer");
        IUserAuthService authService = null;
        if ("weixing-mall-cms".equals(clientId)) {
            authService = sysUserAuthService;
        } else if ("weixing-mall-mem".equals(clientId)) {
            authService = memberAuthService;
        } else if ("weixing-mall-agent".equals(clientId)) {
            authService = agentAuthService;
        }
        OAuth2AccessToken oAuth2AccessToken = sysTokenServices.refreshAccessToken(refreshToken, tokenRequest, authService);
        return ResultUtil.success(oAuth2AccessToken);
    }


    @GetMapping("/token/check")
    public Result<Map<String, Object>> checkToken(String accessToken) {
        OAuth2AccessToken token = sysTokenServices.readAccessToken(accessToken);
        Map<String, Object> response = new HashMap<>();
        if (token == null) {
            response.put("active", false);
            throw new InvalidTokenException("Token was not recognised");
        } else if (token.isExpired()) {
            response.put("active", false);
            throw new InvalidTokenException("Token has expired");
        } else {
            OAuth2Authentication authentication = sysTokenServices.loadAuthentication(token.getValue());
            response = (Map<String, Object>) jwtAccessTokenConverter.convertAccessToken(token, authentication);
            response.put("active", true);

        }
        return ResultUtil.success(response);
    }


    /**
     * 服务端公众号配置
     *
     * @param url  页面地址
     * @return     公众号配置
     */
    @GetMapping("/auth/wxConf")
    public Result<WxConfig> wxConf(String url) {
        System.out.println("当前页URL:"+url);
        return ResultUtil.success(WechatUtil.getWxConfig(url));
    }

    /**
     * 服务端公众号配置
     *
     * @param url  页面地址
     * @return     公众号配置
     */
    @GetMapping("/auth/wxConf/jianAi")
    public Result<WxConfig> jianAiwxConf(String url) {
        System.out.println("当前页URL:"+url);
        return ResultUtil.success(WechatUtil.getJianAiWxConfig(url));
    }


    private ClientDetails getClient(String clientId, String clientSecret, ClientDetailsService clientDetailsService) {
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
        if (clientDetails == null) {
            throw new UnapprovedClientAuthenticationException("clientId对应的信息不存在");
        } else if (!passwordEncoder.matches(clientSecret, clientDetails.getClientSecret())) {
            throw new UnapprovedClientAuthenticationException("clientSecret不匹配");
        }
        return clientDetails;
    }


    /**
     * 方法描述: 自定义异常拦截
     * @Author Small
     * @param e
     * @Date 2020/1/10 15:53
     * @return com.weixing.mall.base.wrapper.Result
     */
    @ResponseBody
    @ExceptionHandler(OAuth2Exception.class)
    public Result handleInvalidTokenException(OAuth2Exception e) {
        return ResultUtil.error(ResultCodeEnum.UNAUTHORIZED.getCode(), e.getMessage());
    }
}
